/*
 This file is part of Musimage, a project which makes possible listen to music
 and, at the same time, watch pictures related with that music.
 Copyright (C) 2006  David Garcia Narbona 

 Musimage is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 Musimage is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Musimage; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package client;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;

import java.io.IOException;

import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.RealizeCompleteEvent;
import javax.media.DurationUpdateEvent;
import javax.media.Time;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.StopEvent;
import javax.media.StartEvent;

import javax.swing.JInternalFrame;
import javax.swing.JOptionPane;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;

import java.net.URL;
import java.net.MalformedURLException;

import java.util.Vector;
import java.util.Enumeration;

public class JMFrame extends JInternalFrame implements ControllerListener {

	// ** Atributos **/////////////////////////////////////////////
	private Player mplayer;

	private Component visual = null;

	private Component control = null;

	private int videoWidth = 0;

	private int videoHeight = 0;

	private int controlHeight = 30;

	private int insetWidth = 10;

	private int insetHeight = 30;

	private String directory;

	private Vector listSongs;

	private Enumeration enumeration;

	private URL url;

	// variable para controlar que fila de la lista de canciones debe aparecer
	// seleccionada
	private int indexSelectedSong;

	// Referencia a la instancia de la clase UpJPanel
	private UpJPanel upJPanel;

	private double songDuration = 0;

	private boolean itsBeenPaused;

	// ///////////////////////////////////////////////////////////

	// ** Metodos **//////////////////////////////////////////////

	// Constructor
	public JMFrame(UpJPanel _upJPanel, String _directory, Vector _listSongs) {

		super((String) _listSongs.firstElement(), true, true, true, true);
		super.setTitle(takeExtension((String) _listSongs.firstElement()));

		directory = _directory;
		listSongs = _listSongs;

		enumeration = listSongs.elements();

		getContentPane().setLayout(new BorderLayout());
		setSize(320, 10);
		setVisible(true);

		url = null;
		mplayer = null;

		upJPanel = _upJPanel;

		indexSelectedSong = 0;

		loadMP3File(directory + (String) enumeration.nextElement());
		mplayer.addControllerListener((ControllerListener) this);
		mplayer.realize();
		addInternalFrameListener(new InternalFrameAdapter() {

			public void internalFrameClosing(InternalFrameEvent ife) {
				mplayer.close();
				upJPanel.clearListSongs();
				listSongs = null;
			}
		});
	}

	// Getter
	public Player getPlayer() {
		return mplayer;
	}

	public void Error(String error) {
		JOptionPane
				.showMessageDialog(
						null,
						"El archivo \""
								+ error
								+ "\" no esta en el mismo directorio que la lista de canciones",
						null, JOptionPane.ERROR_MESSAGE);
	}

	// Metodo que se encarga de inicializar el objeto Player con el recurso
	// multimedia especificado en la URL que deber ecibir por parametro
	private void loadMP3File(String mediaFile) {

		try {

			// Create an url from the file name and the url to the
			// document containing this applet.
			if ((url = new URL(mediaFile)) == null) {

				System.out.println("Can't build URL for " + mediaFile);
				return;
			}

			// Create an instance of a player for this media
			try {

				mplayer = Manager.createPlayer(url);
			} catch (NoPlayerException e) {
				Error(title);
			}

		} catch (MalformedURLException e) {
			System.err
					.println("Error in loadMP3File(String ) - JMFrame class: "
							+ e.getMessage());
		} catch (IOException e) {
			System.err
					.println("Error in loadMP3File(String ) - JMFrame class: "
							+ e.getMessage());
		}
	}

	// Metodo que elimina la extension de los archivos de musica para
	// que la visualizacion del nombre de archivo sea algo mas estetica
	private String takeExtension(String title) {

		return title.substring(0, title.length() - 4);
	}

	// Metodo que destruye la actividad de esta clase, desabilitando el
	// objeto Player y quitando de pantalla el JInternalFrame
	public void destroy() {

		mplayer.close();
		dispose();
	}

	// Metodo que inicia la reproduccion de una cancion seleccionada
	// por el usuario desde la lista
	public void playSong(int indexSong) {

		int i;

		if (mplayer != null) {
			mplayer.stop();
			mplayer.setMediaTime(new Time(0));
		}

		enumeration = null;
		enumeration = listSongs.elements();

		for (i = 0; i < indexSong; i++)
			enumeration.nextElement();

		// se resta uno para que, al llamar al metodo getNextSongToPlay(), para
		// que sirva en distintos
		// casos, cuando se le sume uno quede igual que si se le asignara la i,
		// que seria
		// la situacion normal
		indexSelectedSong = i - 1;

		getNextSongToPlay();
	}

	// Metodo a implementar de la interfaz ControllerListener
	public void controllerUpdate(ControllerEvent ce) {

		if (ce instanceof RealizeCompleteEvent) {

			mplayer.prefetch();
		} else if (ce instanceof DurationUpdateEvent) {

			itsBeenPaused = false;
			songDuration = mplayer.getDuration().getSeconds();
		} else if (ce instanceof PrefetchCompleteEvent) {

			if (visual != null)
				return;

			if ((visual = mplayer.getVisualComponent()) != null) {

				Dimension size = visual.getPreferredSize();
				videoWidth = size.width;
				videoHeight = size.height;
				getContentPane().add("Center", visual);
			} else
				videoWidth = 320;

			upJPanel.setListTrackSelected(indexSelectedSong, songDuration);

			if ((control = mplayer.getControlPanelComponent()) != null) {

				controlHeight = control.getPreferredSize().height;
				getContentPane().add("South", control);
			}

			setSize(videoWidth + insetWidth, videoHeight + controlHeight
					+ insetHeight);
			validate();
			mplayer.start();
		} else if (ce instanceof EndOfMediaEvent) {

			// Se controla que cuando termine una cancion empiece la siguiente
			// de la lista si quedan, si no o para o vuelve a empezar
			// segun la opcion que eljia el usuario de auto-replay o no
			if (enumeration.hasMoreElements())
				getNextSongToPlay();
			else if (upJPanel.getAutoReplay()) {
				getNextSongToPlay();
			} else
				mplayer.setMediaTime(new Time(0));
		} else if (ce instanceof StopEvent) {

			itsBeenPaused = true;
		} else if (ce instanceof StartEvent && itsBeenPaused) {

			itsBeenPaused = false;
		}
	}

	// Metodo interno de la clase que se llama para poner todo a punto
	// para empezar una nueva reproduccion a continuacion de la anterior
	private void getNextSongToPlay() {

		String title;

		indexSelectedSong = indexSelectedSong + 1;

		// Si se acaba la lista de canciones y esta activado el auto-replay
		if (indexSelectedSong == listSongs.size()) {

			indexSelectedSong = 0;
			enumeration = listSongs.elements();
		}

		title = (String) enumeration.nextElement();
		super.setTitle(takeExtension(title));

		if (mplayer != null)
			remove(mplayer.getControlPanelComponent());
		mplayer = null;

		loadMP3File(directory + title);

		try {
			mplayer.addControllerListener((ControllerListener) this);
			mplayer.realize();
			mplayer.start();
		} catch (NullPointerException e) {

			mplayer = null;
			Error(title);
		}
	}

	// ////////////////////////////////////////////////////////////
}
